﻿using System;
using UnityEngine;

namespace Z1029.PhiPlayer.OpenSource
{
    public class Note : MonoBehaviour
    {
        [HideInInspector]
        public NoteType type;
        public Direction direction;
        public NoteData noteData;
        public int noteSoundID;

        [Tooltip("HL Sprite")]
        public Sprite HighLight;
        public SpriteRenderer thisRenderer;
        public JudgementLine judgeline;
        public bool isRegistered;

        public virtual void Awake()
        {
        }

        public virtual void OnNoteStart()
        {
        }

        public virtual void Start()
        {
            isRegistered = false;
            noteData.time = Utils.GetTimeFromBeatTime(noteData.beatTime, judgeline.bpm);
            noteData.holdTime = Utils.GetTimeFromBeatTime(noteData.beatHoldTime, judgeline.bpm);
            thisRenderer.color = Color.white;
            transform.localScale = new Vector3(LevelController.noteSize + LevelController.instance.noteSizeOffset, LevelController.noteSize + LevelController.instance.noteSizeOffset, 1f);
            transform.localEulerAngles = Vector3.zero;
            OnNoteStart();
        }

        public void SetNoteHighLight()
        {
            if (HLNote(noteData.beatTime))
            {
                thisRenderer.sprite = HighLight;
            }
        }

        public virtual float CalculateNotePosY()
        {
            float num = CalculateDistance();
            if (direction == Direction.Below)
            {
                num = -num;
            }
            float realY = transform.localPosition.y + (num - transform.localPosition.y);
            return realY;
        }

        public virtual float CalculateDistance()
        {
            return (noteData.speed * judgeline.GetSpeedDistance(noteData.time));
        }

        public virtual void SetNotePosition()
        {
            transform.localPosition = new Vector3(noteData.positionX, CalculateNotePosY(), 0f);
        }

        public virtual void ChangeToMissColor()
        {
            thisRenderer.color = new Color(1f, 1f, 1f, 0.5f);
        }

        public virtual void UpdateNoteMiss()
        {
            if (noteData.time - LevelController.nowTime < 0f)
            {
                ChangeToMissColor();
                if (noteData.time - LevelController.nowTime < -0.18f)
                {
                    MissNote();
                    Hit(HitACC.Miss);
                }
            }
        }

        public virtual void Update()
        {
            SetNotePosition();
            UpdateNoteMiss();
            OnNoteUpdate();
            //else 
            ///Auto
            //if (LevelController.nowTime > noteData.time) OnHit(HitACC.Perfect);
        }

        public virtual void Hit(HitACC acc)
        {
            LevelController ctl = LevelController.instance;
            RemoveNearJudgeNotes();
            switch (acc)
            {
                case HitACC.Perfect:
                    ctl.AddScore(HitACC.Perfect);
                    transform.localPosition = new Vector3(transform.localPosition.x, 0, 0);
                    ctl.hitEffectManager.ShowEffect(acc, transform.position, transform.parent, noteSoundID, type);
                    Destroy(gameObject);
                    return;
                case HitACC.Good:
                    ctl.AddScore(HitACC.Good);
                    transform.localPosition = new Vector3(transform.localPosition.x, 0, 0);
                    ctl.hitEffectManager.ShowEffect(acc, transform.position, transform.parent, noteSoundID, type);
                    Destroy(gameObject);
                    return;
                case HitACC.Bad:
                    ctl.AddScore(HitACC.Bad);
                    ctl.hitEffectManager.ShowEffect(acc, transform.position, transform.parent, noteSoundID, type);
                    Destroy(gameObject);
                    return;
                case HitACC.Miss:
                    ctl.AddScore(HitACC.Miss);
                    Destroy(gameObject);
                    return;
                default:
                    Debug.LogError(string.Format("This note \"{0}\" not judged!!! Check logic!", this));
                    return;
            }
        }

        public virtual void OnNoteUpdate()
        {
        }

        public virtual HitACC JudgeNote()
        {
            return HitACC.Perfect;
        }

        public virtual void UpdateJudgeNote()
        {

        }

        public virtual void AddToNearJudgeNotes()
        {
            if (!isRegistered)
            {
                judgeline.nearJudgeNotes.Add(this);
                isRegistered = true;
            }
        }

        public virtual void RemoveNearJudgeNotes()
        {
            if (isRegistered)
            {
                judgeline.nearJudgeNotes.Remove(this);
                isRegistered = false;
            }
        }

        public void MissNote()
        {
            RemoveNearJudgeNotes();
            LevelController.instance.FCAPState = LevelController.FCAP.None;
            LevelController.instance.combo = 0;
            //OverUI.missCount++;
        }

        public static bool HLNote(int beatTime)
        {
            int count = 0;
            for (int i = 0; i < LevelController.instance.notes.Length; i++)
            {
                if (LevelController.instance.notes[i].noteData.beatTime == beatTime)
                {
                    count++;
                }
            }
            return count >= 2;
        }

        [Serializable]
        public struct NoteData
        {
            public NoteType type;
            public double time;
            public float positionX;
            public float speed;
            public double holdTime;
            public int beatTime;
            public int beatHoldTime;
            public int index;
        }
        public enum Direction
        {
            Above, Below
        }
        public enum HitACC
        {
            Perfect, Good, Bad, Miss
        }
    }

    public enum NoteType
    {
        Click, Drag, Hold, Flick
    }
}